home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Celestin Apprentice 4
/
Apprentice-Release4.iso
/
Source Code
/
PowerPlant
/
UWindowUsher 1.1
/
UWindowsUsher.cp
< prev
next >
Wrap
Text File
|
1995-08-28
|
20KB
|
783 lines
// ===========================================================================
// UWindowsUsher.cp © 1995, Éric Forget. All rights reserved.
// ===========================================================================
//
// ************************************************************************
// * *
// * Before using this code you should read the "License Agreement" *
// * document and agree with it. *
// * *
// ************************************************************************
//
//
// This module try to place your windows to their *right* place!
// It also manage your Window menu.
//
// In version 1.1, UWindowUsher now deal correctly with standard size.
//
// ---------------------------------------------------------------------------
//
// Instruction Notes:
// -----------------
//
// 1) Add this line in your CXXXApp (Application class) constructor:
//
// UWindowsUsher::Initialize();
//
// *OR* this line if you have a Window Menu:
//
// UWindowsUsher::Initialize(myWindowMenuID);
//
//
// 2) Add this line of code where you create your document’s window:
//
// UWindowsUsher::AddWindow(myLWindow, myShowIt);
//
// *OR* this line if you want modified document to be underlined:
//
// UWindowsUsher::AddWindow(myLWindow, myShowIt, this);
//
//
// 3) Add this line of code where you delete your document’s window:
//
// UWindowsUsher::RemoveWindow(myLWindow);
//
//
// 4) Normally, use the command number 30 to your Stack Windows item.
// If you do this, it will be enabled and disabled automatically.
// To do this put use the 'Mcmd' resource. But, optionally you
// may call directly:
//
// UWindowsUsher::Stack();
//
//
// 5) That’s all. If you have problems, find a bug (hopefully not!)
// or if you just like it, drop me a message at my e-mail address:
//
// ForgetE@eWorld.com
//
//
// ---------------------------------------------------------------------------
//
// Usage Notes:
// -----------
//
// 1) (from UDesktop.cp)
// You must call UScreenPort::Initialize() before using this
// class. Since you only need to call it once, the best place
// to call UScreenPort::Initialize() is in the constructor for
// your Application class.
//
// 2) You must call UWindowsUsher::Dispose() before exiting a code resource
// if you don’t need the leak… :-)
//
// 3) I have use a command reserved for the cmd_StackWindows in hoping
// that MetroWerks will add it to their *reserved* list...
//
// ---------------------------------------------------------------------------
#ifdef PowerPlant_PCH
#include PowerPlant_PCH
#endif
#include "UWindowsUsher.h"
#include <LAttachable.h>
#include <LCommander.h>
#include <LDocument.h>
#include <LMenu.h>
#include <LMenuBar.h>
#include <LList.h>
#include <LWindow.h>
#include <String_Utils.h>
#include <UDrawingState.h>
#include <UScreenPort.h>
#ifndef __RESOURCES__
#include <Resources.h>
#endif
#ifndef __LOWMEM__
#include <LowMem.h>
#endif
#ifndef __TOOLUTILS__
#include <ToolUtils.h>
#endif
#ifndef __ERRORS__
#include <Errors.h>
#endif
#ifndef __MENUS__
#include <Menus.h>
#endif
// ---------------------------------------------------------------------------
// • Static Member Variable
// ---------------------------------------------------------------------------
LList *UWindowsUsher::sWindowList = nil;
LList *UWindowsUsher::sAttachmentList = nil;
ResIDT UWindowsUsher::sWindowMenuID = Menu_Undefined;
LCommander *UWindowsUsher::sApplication = nil;
LAttachment *UWindowsUsher::sStackAttachment = nil;
// ---------------------------------------------------------------------------
// • Constants
// ---------------------------------------------------------------------------
const Int16 Int16_LeftShift = 5;
const Int16 Int16_TopShift = 18;
const Int16 Int16_BottomShift = 5;
const Int16 Int16_RightShift = 5;
const Int16 Int16_TopMargin = 5;
const Int16 Int16_RightMargin = 80;
const Int16 Int16_BottomMargin = 30;
const Int16 Int16_WindowsCount = 5;
// ===========================================================================
// • UWindowsUsher UWindowsUsher •
// ===========================================================================
// ---------------------------------------------------------------------------
// • Initialize
// ---------------------------------------------------------------------------
void
UWindowsUsher::Initialize(
ResIDT inWindowMenuID)
{
if (sWindowList != nil) { // Do nothing if already initialized
return;
}
if((sWindowMenuID = inWindowMenuID) != Menu_Undefined) {
// Find the Super Commander of all!
LCommander *tempTarget = LCommander::GetTarget();
while(tempTarget != nil) {
sApplication = tempTarget;
tempTarget = sApplication->GetSuperCommander();
}
sAttachmentList = new LList(sizeof(LAttachment *));
sStackAttachment = new LStackCmdAttachment();
}
// Allocate the window list
sWindowList = new LList(sizeof(LWindow *));
}
// ---------------------------------------------------------------------------
// • Dispose
// ---------------------------------------------------------------------------
void
UWindowsUsher::Dispose()
{
if (sWindowList == nil) { // Do nothing if not initialized
return;
}
// Delete the window list
delete sWindowList;
sWindowList = nil;
if(sApplication != nil) {
if(sStackAttachment != nil) {
sApplication->RemoveAttachment(sStackAttachment);
delete sStackAttachment;
}
}
if(sAttachmentList != nil) {
delete sAttachmentList;
}
}
// ---------------------------------------------------------------------------
// • AddWindow
// ---------------------------------------------------------------------------
// Add the window to the list and stack it to the first empty place.
void
UWindowsUsher::AddWindow(
LWindow *inWindow,
Boolean inShowIt,
LDocument *inDocument)
{
Assert_(sWindowList != nil);
Assert_(inWindow != nil);
Assert_(sWindowList->GetCount() <= max_Int16); // Will you really add more than max_Int16?
LWindow *dummyWindow = inWindow; // Could be initialize to any value except nil!
Int32 itemNo;
volatile LWindowMenuAttachment *anAttachment = nil;
Try_ {
// Check for an empty slot...
for(itemNo = 1; (itemNo <= sWindowList->GetCount()) && (dummyWindow != nil); itemNo++) {
sWindowList->FetchItemAt(itemNo, &dummyWindow);
if(dummyWindow == nil) {
itemNo--;
}
}
// Append the window or put it the empty slot...
if(itemNo > sWindowList->GetCount()) {
sWindowList->InsertItemsAt(1, itemNo, &inWindow);
} else {
sWindowList->SetItemAt(itemNo, &inWindow);
}
// Stack the window at its position...
StackAtPos(itemNo, inWindow);
// Add the window name to the Windows menu
if((sWindowMenuID != Menu_Undefined) && (sApplication != nil)) {
anAttachment = new LWindowMenuAttachment(inWindow, sWindowMenuID, inDocument);
sApplication->AddAttachment(anAttachment, nil, false);
// Append the window or put it the empty slot...
if(itemNo > sAttachmentList->GetCount()) {
sAttachmentList->InsertItemsAt(1, itemNo, &anAttachment);
} else {
sAttachmentList->SetItemAt(itemNo, &anAttachment);
}
if(itemNo == 1) {
sApplication->AddAttachment(sStackAttachment, nil, false);
}
}
} Catch_(inErr) {
// if in a rare situation we have lacked RAM...
if(sAttachmentList != nil) {
// sAttachmentList and sWindowList must have the same size!
if(sAttachmentList->GetCount() < sWindowList->GetCount()) {
sWindowList->RemoveItemsAt(1, sWindowList->GetCount());
// a possible leak...
if(anAttachment != nil) {
delete anAttachment;
}
}
}
} EndCatch_
// Show the window if necesary...
if(inShowIt) {
inWindow->Show();
}
}
// ---------------------------------------------------------------------------
// • RemoveWindow
// ---------------------------------------------------------------------------
// RemoveWindow the window from the list.
void
UWindowsUsher::RemoveWindow(
LWindow *inWindow)
{
Assert_(sWindowList != nil);
Assert_(inWindow != nil);
Int32 index = sWindowList->FetchIndexOf(&inWindow);
Int32 dummyPtr = nil;
Assert_(index); // Hey, it would be faster in release version if I it doesn’t
// have to check for this...
dummyPtr = nil;
sWindowList->SetItemAt(index, &dummyPtr);
if(index == sWindowList->GetCount()) {
// It was the last so remove it...
// ...and all empty slots at the end
do {
sWindowList->FetchItemAt(sWindowList->GetCount(), &dummyPtr);
if(dummyPtr == nil) {
sWindowList->RemoveItemsAt(1, sWindowList->GetCount());
}
} while((dummyPtr == nil) && sWindowList->GetCount());
}
if((sWindowList->GetCount() == 0) && (sApplication != nil)) {
sApplication->RemoveAttachment(sStackAttachment);
}
if((sWindowMenuID != Menu_Undefined) && (sApplication != nil)) {
LWindowMenuAttachment *anAttachment;
CommandT cmdRemoved;
sAttachmentList->FetchItemAt(index, &anAttachment);
dummyPtr = nil;
sAttachmentList->SetItemAt(index, &dummyPtr);
if(index == sAttachmentList->GetCount()) {
// It was the last so remove it...
// ...and all empty slots at the end
do {
sAttachmentList->FetchItemAt(sAttachmentList->GetCount(), &dummyPtr);
if(dummyPtr == nil) {
sAttachmentList->RemoveItemsAt(1, sAttachmentList->GetCount());
}
} while((dummyPtr == nil) && sWindowList->GetCount());
}
if(anAttachment != nil) { // We are never too careful!
sApplication->RemoveAttachment(anAttachment);
cmdRemoved = anAttachment->GetCommand();
delete anAttachment;
// Tell all attachment that one of their pears has been removed...
LListIterator iterator(*sAttachmentList, iterate_FromStart);
while (iterator.Next(&anAttachment)) {
if(anAttachment != nil) {
anAttachment->AttachmentHasBeenRemoved(cmdRemoved);
}
}
}
}
}
// ---------------------------------------------------------------------------
// • GetWindowCount
// ---------------------------------------------------------------------------
Int16
UWindowsUsher::GetWindowCount()
{
return sWindowList->GetCount();
}
// ---------------------------------------------------------------------------
// • IsStackEnabled
// ---------------------------------------------------------------------------
// Return true if there is at least on window in the list...
Boolean
UWindowsUsher::IsStackEnabled()
{
return (sWindowList->GetCount() > 0) && (!UDesktop::FrontWindowIsModal());
}
// ---------------------------------------------------------------------------
// • Stack
// ---------------------------------------------------------------------------
// Stack all windows.
void
UWindowsUsher::Stack()
{
Assert_(sWindowList != nil);
Int32 windowNo = 1;
LWindow *ppWindow = nil;
Int32 index;
WindowPtr theWindowP;
CursHandle watchCursorH;
Cursor watchCopy;
// Change the cursor to the watch...
watchCursorH = ::GetCursor(watchCursor);
watchCopy = **watchCursorH;
::SetCursor(&watchCopy);
// For each slot in the list...
for(Int32 i = 1; i <= sWindowList->GetCount(); i++) {
// ... find the right PowerPlant’s LWindow...
do {
do {
theWindowP = UWindows::FindNthWindow(windowNo++);
ppWindow = LWindow::FetchWindowObject(theWindowP);
} while((ppWindow == nil) && (theWindowP != nil));
index = sWindowList->FetchIndexOf(&ppWindow);
} while((index == arrayIndex_Bad) && (theWindowP != nil));
// If we have find a good PowerPlant’s LWindow...
if((index != arrayIndex_Bad) && (ppWindow != nil)) {
// We need to swap because windows order may have changed...
sWindowList->SwapItems(i, index);
sAttachmentList->SwapItems(i, index);
// Do the job!
StackAtPos(i, ppWindow);
}
}
// Remove empty slots...
while(sWindowList->FetchItemAt(sWindowList->GetCount(), &ppWindow)) {
if(ppWindow == nil) {
// // Remove an empty slot...
sAttachmentList->RemoveItemsAt(1, sWindowList->GetCount());
sWindowList->RemoveItemsAt(1, sWindowList->GetCount());
} else {
break; // All empty slot have been removed!
}
}
::SetCursor(&UQDGlobals::GetQDGlobals()->arrow);
}
// ---------------------------------------------------------------------------
// • StackAtPos
// ---------------------------------------------------------------------------
// Stack a window.
void
UWindowsUsher::StackAtPos(
Int16 inPos,
LWindow *inWindow)
{
// Some tricky code to translate in five slots...
Int16 realPos = ((inPos - 1) % Int16_WindowsCount) + 1;
Rect windowBounds = UScreenPort::GetScreenPort()->portRect;
SDimension16 stdSize;
Boolean resizeable = inWindow->HasAttribute(windAttr_Resizable);
inWindow->GetStandardSize(stdSize);
// The magic code!
windowBounds.top += Int16_TopMargin + realPos * Int16_TopShift;
windowBounds.left += realPos * Int16_LeftShift;
if (resizeable && stdSize.height > windowBounds.bottom) {
windowBounds.bottom -= Int16_BottomMargin - realPos * Int16_BottomShift;
} else {
windowBounds.bottom = windowBounds.top + stdSize.height;
}
if (resizeable && stdSize.width > windowBounds.right) {
windowBounds.right -= Int16_RightMargin - realPos * Int16_RightShift;
} else {
windowBounds.right = windowBounds.left + stdSize.width;
}
inWindow->DoSetBounds(windowBounds);
}
// ===========================================================================
// • LWindowMenuAttachment LWindowMenuAttachment •
// ===========================================================================
// ---------------------------------------------------------------------------
// • Static Member Variable
// ---------------------------------------------------------------------------
Int16 LWindowMenuAttachment::sDecalItem = 0;
// ---------------------------------------------------------------------------
// • LWindowMenuAttachment
// ---------------------------------------------------------------------------
LWindowMenuAttachment::LWindowMenuAttachment(
LWindow *inWindow,
ResIDT inWindowMenuID,
LDocument *inDocument)
{
mWindowMenuID = inWindowMenuID;
mWindow = inWindow;
mDocument = inDocument;
LMenu *theMenu;
// Find the menu
if((theMenu = LMenuBar::GetCurrentMenuBar()->FetchMenu(mWindowMenuID)) != nil) {
Str255 itemText = "\p(-"; // A separator item
Int16 index = UWindowsUsher::GetWindowCount();
// Append a separator before the first window’s title
if((index == 1) ||
(CountMItems(theMenu->GetMacMenuH()) < sDecalItem)) {
theMenu->InsertCommand(itemText, cmd_UseMenuItem, max_Int16 - 1);
sDecalItem = CountMItems(theMenu->GetMacMenuH());
}
index = CountMItems(theMenu->GetMacMenuH()) + 1;
inWindow->GetDescriptor(itemText);
// Add a shortcut for the first 9 windows...
if((index - sDecalItem) <= 9) {
Str255 tempString;
::NumToString(index - sDecalItem, tempString);
::ConcatPStr(itemText, "\p/");
::ConcatPStr(itemText, tempString);
}
theMenu->InsertCommand(itemText, cmd_UseMenuItem, max_Int16 - 1);
// My command that I will have to manage...
mCmdToManage = theMenu->SyntheticCommandFromIndex(CountMItems(theMenu->GetMacMenuH()));
}
}
// ---------------------------------------------------------------------------
// • ~LWindowMenuAttachment
// ---------------------------------------------------------------------------
LWindowMenuAttachment::~LWindowMenuAttachment()
{
LMenu *theMenu;
if((theMenu = LMenuBar::GetCurrentMenuBar()->FetchMenu(mWindowMenuID)) != nil) {
theMenu->RemoveCommand(mCmdToManage);
// If we were alone... clean up the Window Menu
if(UWindowsUsher::GetWindowCount() == 0) {
theMenu->RemoveCommand(theMenu->SyntheticCommandFromIndex(sDecalItem));
}
}
}
// ---------------------------------------------------------------------------
// • AttachmentHasBeenRemoved
// ---------------------------------------------------------------------------
void
LWindowMenuAttachment::AttachmentHasBeenRemoved(
CommandT inCommand)
{
LMenu *theMenu;
Int16 oldIndex = (Int16) (-mCmdToManage);
Int16 oldIndexRemoved = (Int16) (-inCommand);
if(((theMenu = LMenuBar::GetCurrentMenuBar()->FetchMenu(mWindowMenuID)) != nil) &&
(oldIndex > oldIndexRemoved)) {
mCmdToManage = theMenu->SyntheticCommandFromIndex(oldIndex - 1);
if((oldIndex - sDecalItem) <= 10) { // Our shortcut is downsizing...
::SetItemCmd(theMenu->GetMacMenuH(), oldIndex - 1, '0' + (oldIndex - 1 - sDecalItem));
}
}
}
// ---------------------------------------------------------------------------
// • GetCommand
// ---------------------------------------------------------------------------
CommandT
LWindowMenuAttachment::GetCommand()
{
return mCmdToManage;
}
// ---------------------------------------------------------------------------
// • ExecuteSelf
// ---------------------------------------------------------------------------
void
LWindowMenuAttachment::ExecuteSelf(
MessageT inMessage,
void *ioParam)
{
mExecuteHost = true;
switch(inMessage) {
case msg_CommandStatus:
SCommandStatusP theCmdStatus = ((SCommandStatusP) ioParam);
if(theCmdStatus->command == mCmdToManage) {
// We use mark to show the active window!
*theCmdStatus->usesMark = true;
if(UDesktop::WindowIsSelected(mWindow)) {
*theCmdStatus->mark = checkMark;
} else {
*theCmdStatus->mark = noMark;
}
// If document as been specified...
if(mDocument != nil) {
LMenu *theMenu = LMenuBar::GetCurrentMenuBar()->FetchMenu(mWindowMenuID);
Int16 index = theMenu->IndexFromCommand(mCmdToManage);
if(mDocument->IsModified()) {
// It should be underline...
::SetItemStyle(theMenu->GetMacMenuH(), index, underline);
} else {
// It shouldn’t be underline...
::SetItemStyle(theMenu->GetMacMenuH(), index, 0);
}
}
// It may slowdown the execution, but it make change from
// your window name transparent...
mWindow->GetDescriptor(theCmdStatus->name);
// Always enabled except if the front window is modal!
*theCmdStatus->enabled = !UDesktop::FrontWindowIsModal();
mExecuteHost = false; // Don’t ask the host
}
break;
default:
if(inMessage == mCmdToManage) {
// Do our difficult job :-) !
UDesktop::SelectDeskWindow(mWindow);
mExecuteHost = false; // Don’t ask the host
}
break;
}
}
// ===========================================================================
// • LStackCmdAttachment LStackCmdAttachment •
// ===========================================================================
// ---------------------------------------------------------------------------
// • ExecuteSelf
// ---------------------------------------------------------------------------
void
LStackCmdAttachment::ExecuteSelf(
MessageT inMessage,
void *ioParam)
{
mExecuteHost = true;
switch(inMessage) {
case msg_CommandStatus:
SCommandStatusP theCmdStatus = ((SCommandStatusP) ioParam);
if(theCmdStatus->command == cmd_StackWindows) {
// Enable only if there is at least one window in the list!
// *theCmdStatus->enabled = true;//UWindowsUsher::IsStackEnabled();
*theCmdStatus->enabled = UWindowsUsher::IsStackEnabled();
mExecuteHost = false; // Don’t ask the host
}
break;
case cmd_StackWindows:
UWindowsUsher::Stack(); // Do our difficult job :-) !
mExecuteHost = false; // Don’t ask the host
break;
}
}